#include "InputSystem.h"
#include "InputBuffer.h"
#include "../control/Script.h"
#include "../tools/Log.h"

#include <sys/select.h>
#include <GL/glfw.h>

void InputSystem::kill() {}

void InputSystem::terminate() {}

void InputSystem::update(long) {
	checkstdIn();
}

void InputSystem::setFocus(InputInterface* i)
{	currentInterface = i; }

void InputSystem::checkstdIn() {
	fd_set stdinfd;
	FD_ZERO( &stdinfd );
	FD_SET( STDIN_FILENO, &stdinfd );
	struct timeval tv;
	tv.tv_sec = 0;
	tv.tv_usec = 0;
	int ready = select( 1, &stdinfd, NULL, NULL, &tv );
	if(ready) {
		//We read things from standard in, so dispatch it
		userInput->process();
		lout<<"> ";
	}
}

void callbackOnMousePosChange(int x, int y) {
	if(InputSystem::Instance().currentInterface == NULL) return;
	int height = 0;
	glfwGetWindowSize(NULL, &height);
	//Invert the y so (0,0) is lower left
	InputSystem::Instance().currentInterface->onMouseMove(x, height - y);
}

void callbackOnMouseButtonChange(KEY_TYPE KEY, int action) {
	if(InputSystem::Instance().currentInterface == NULL) return;
	
	int mouseX, mouseY;
	glfwGetMousePos(&mouseX, &mouseY);
	int height = 0;
	glfwGetWindowSize(NULL, &height);
	//Invert the y so (0,0) is lower left
	if(action == GLFW_RELEASE)
		InputSystem::Instance().currentInterface->onMouseButtonUp(KEY, mouseX, height - mouseY);
	else
		InputSystem::Instance().currentInterface->onMouseButtonDown(KEY, mouseX, height - mouseY);
}

void callbackOnKeyboardButtonChange(KEY_TYPE KEY, int action)
{
	if(InputSystem::Instance().currentInterface == NULL) return;
	
	if(action == GLFW_RELEASE)
		InputSystem::Instance().currentInterface->onKeyUp(KEY);
	else
		InputSystem::Instance().currentInterface->onKeyDown(KEY);
}

void callbackOnMouseWheelChange(int newPos) {
	static int pos = glfwGetMouseWheel();
	
	//We want mouse wheel change, not actual position since that differs per mouse
	if(pos < newPos) 
		InputSystem::Instance().currentInterface->onMouseWheelDown();
	else if(pos > newPos)
		InputSystem::Instance().currentInterface->onMouseWheelUp();
		
	pos = newPos;
}

bool InputSystem::init(const CmdLineArgs&)
{
	//register the functions
	glfwSetMousePosCallback(&callbackOnMousePosChange);
	glfwSetMouseButtonCallback(&callbackOnMouseButtonChange);
	glfwSetKeyCallback(&callbackOnKeyboardButtonChange);
	glfwSetMouseWheelCallback(&callbackOnMouseWheelChange);

	//dispatch things from standard in to script
	userInput = new InputBuffer(STDIN_FILENO, Script::process);
	if(userInput == NULL) return false;
	buildKeyNameMap();
	
	return true;
}

InputSystem::InputSystem()
: currentInterface(NULL)
, userInput(NULL)
, keyNames()
{}

KEY_TYPE getKey(const std::string& s) {
	std::map<std::string, KEY_TYPE>::iterator itr = InputSystem::Instance().keyNames.find(s);
	if(itr == InputSystem::Instance().keyNames.end()) {
		//if we didn't find it, but only had a single character, convert that character to an int
		// For example, " " becomes 32
		if(s.size() == 1)		
			return (int)s[0];
		//It was something invalid, so say void
		return KEY_VOID;
	}
	return itr->second;
}

//This was so much fun to write.... :-(
void InputSystem::buildKeyNameMap() {
	keyNames[""] = KEY_VOID;
	keyNames["Left Arrow"] = KEY_LEFT_ARROW;
	keyNames["Right Arrow"] = KEY_RIGHT_ARROW;
	keyNames["Up Arrow"] = KEY_UP_ARROW;
	keyNames["Down Arrow"] = KEY_DOWN_ARROW;
	keyNames["Escape"] = KEY_ESC;
	keyNames["F1"] = KEY_F1;
	keyNames["F2"] = KEY_F2;
	keyNames["F3"] = KEY_F3;
	keyNames["F4"] = KEY_F4;
	keyNames["F5"] = KEY_F5;
	keyNames["F6"] = KEY_F6;
	keyNames["F7"] = KEY_F7;
	keyNames["F8"] = KEY_F8;
	keyNames["F9"] = KEY_F9;
	keyNames["F10"] = KEY_F10;
	keyNames["F11"] = KEY_F11;
	keyNames["F12"] = KEY_F12;
	keyNames["Left Shift"] = KEY_LSHIFT;
	keyNames["Right Shift"] = KEY_RSHIFT;
	keyNames["Left Control"] = KEY_LCTRL;
	keyNames["Right Control"] = KEY_RCTRL;
	keyNames["Left Alt"] = KEY_LALT;
	keyNames["Right Alt"] = KEY_RALT;
	keyNames["Tab"] = KEY_TAB;
	keyNames["Enter"] = KEY_ENTER;
	keyNames["Backspace"] = KEY_BACKSPACE;
	keyNames["Insert"] = KEY_INSERT;
	keyNames["Delete"] = KEY_DEL;
	keyNames["Page Up"] = KEY_PAGEUP;
	keyNames["Page Down"] = KEY_PAGEDOWN;
	keyNames["Home"] = KEY_HOME;
	keyNames["End"] = KEY_END;
	keyNames["Pad 0"] = KEY_KP_0;
	keyNames["Pad 1"] = KEY_KP_1;
	keyNames["Pad 2"] = KEY_KP_2;
	keyNames["Pad 3"] = KEY_KP_3;
	keyNames["Pad 4"] = KEY_KP_4;
	keyNames["Pad 5"] = KEY_KP_5;
	keyNames["Pad 6"] = KEY_KP_6;
	keyNames["Pad 7"] = KEY_KP_7;
	keyNames["Pad 8"] = KEY_KP_8;
	keyNames["Pad 9"] = KEY_KP_9;
	keyNames["Pad Divide"] = KEY_KP_DIVIDE;
	keyNames["Pad Multiply"] = KEY_KP_MULTIPLY;
	keyNames["Pad Subtract"] = KEY_KP_SUBTRACT;
	keyNames["Pad Add"] = KEY_KP_ADD;
	keyNames["Pad Decimal"] = KEY_KP_DECIMAL;
	keyNames["Pad Equal"] = KEY_KP_EQUAL;
	keyNames["Pad Enter"] = KEY_KP_ENTER;
	keyNames["Mouse Left"] = MOUSE_BUTTON_LEFT;
	keyNames["Mouse Right"] = MOUSE_BUTTON_RIGHT;
	keyNames["Mouse Middle"] = MOUSE_BUTTON_MIDDLE;
}

const int KEY_VOID = -1;
//If you have a key, test key > SPECIAL_KEY to see if it's a special key or normal key
const int SPECIAL_KEY = GLFW_KEY_SPECIAL;
const int KEY_LEFT_ARROW = GLFW_KEY_LEFT;
const int KEY_RIGHT_ARROW = GLFW_KEY_RIGHT;
const int KEY_UP_ARROW = GLFW_KEY_UP;
const int KEY_DOWN_ARROW = GLFW_KEY_DOWN;
const int KEY_ESC = GLFW_KEY_ESC;
const int KEY_F1 = GLFW_KEY_F1;
const int KEY_F2 = GLFW_KEY_F2;
const int KEY_F3 = GLFW_KEY_F3;
const int KEY_F4 = GLFW_KEY_F4;
const int KEY_F5 = GLFW_KEY_F5;
const int KEY_F6 = GLFW_KEY_F6;
const int KEY_F7 = GLFW_KEY_F7;
const int KEY_F8 = GLFW_KEY_F8;
const int KEY_F9 = GLFW_KEY_F9;
const int KEY_F10 = GLFW_KEY_F10;
const int KEY_F11 = GLFW_KEY_F11;
const int KEY_F12 = GLFW_KEY_F12;
const int KEY_LSHIFT = GLFW_KEY_LSHIFT;
const int KEY_RSHIFT = GLFW_KEY_RSHIFT;
const int KEY_LCTRL = GLFW_KEY_LCTRL;
const int KEY_RCTRL = GLFW_KEY_RCTRL;
const int KEY_LALT = GLFW_KEY_LALT;
const int KEY_RALT = GLFW_KEY_RALT;
const int KEY_TAB = GLFW_KEY_TAB;
const int KEY_ENTER = GLFW_KEY_ENTER;
const int KEY_BACKSPACE = GLFW_KEY_BACKSPACE;
const int KEY_INSERT = GLFW_KEY_INSERT;
const int KEY_DEL = GLFW_KEY_DEL;
const int KEY_PAGEUP = GLFW_KEY_PAGEUP;
const int KEY_PAGEDOWN = GLFW_KEY_PAGEDOWN;
const int KEY_HOME = GLFW_KEY_HOME;
const int KEY_END = GLFW_KEY_END;
const int KEY_KP_0 = GLFW_KEY_KP_0;
const int KEY_KP_1 = GLFW_KEY_KP_1;
const int KEY_KP_2 = GLFW_KEY_KP_2;
const int KEY_KP_3 = GLFW_KEY_KP_3;
const int KEY_KP_4 = GLFW_KEY_KP_4;
const int KEY_KP_5 = GLFW_KEY_KP_5;
const int KEY_KP_6 = GLFW_KEY_KP_6;
const int KEY_KP_7 = GLFW_KEY_KP_7;
const int KEY_KP_8 = GLFW_KEY_KP_8;
const int KEY_KP_9 = GLFW_KEY_KP_9;
const int KEY_KP_DIVIDE = GLFW_KEY_KP_DIVIDE;
const int KEY_KP_MULTIPLY = GLFW_KEY_KP_MULTIPLY;
const int KEY_KP_SUBTRACT = GLFW_KEY_KP_SUBTRACT;
const int KEY_KP_ADD = GLFW_KEY_KP_ADD;
const int KEY_KP_DECIMAL = GLFW_KEY_KP_DECIMAL;
const int KEY_KP_EQUAL = GLFW_KEY_KP_EQUAL;
const int KEY_KP_ENTER = GLFW_KEY_KP_ENTER;
const int MOUSE_BUTTON_LEFT = GLFW_MOUSE_BUTTON_LEFT;
const int MOUSE_BUTTON_RIGHT = GLFW_MOUSE_BUTTON_RIGHT;
const int MOUSE_BUTTON_MIDDLE = GLFW_MOUSE_BUTTON_MIDDLE;


